package com.cmcc.volte.xdr.XDRUtil;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.InetAddress;
import java.net.URLDecoder;
import java.net.UnknownHostException;
import java.sql.Date;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import com.cmcc.volte.xdr.SigXDR.SigXDR;
import com.cmcc.volte.xdr.SigXDR.SigXDRReassemble;
import com.cmcc.volte.xdr.SigXDR.SigXDRSctpReassemble;
import com.cmcc.volte.xdr.sequence.Arrow;
import com.google.common.hash.HashCode;

import dk.i1.diameter.AVP;
import dk.i1.diameter.AVP_Address;
import dk.i1.diameter.AVP_Float32;
import dk.i1.diameter.AVP_Float64;
import dk.i1.diameter.AVP_Grouped;
import dk.i1.diameter.AVP_Integer32;
import dk.i1.diameter.AVP_Integer64;
import dk.i1.diameter.AVP_OctetString;
import dk.i1.diameter.AVP_Time;
import dk.i1.diameter.AVP_UTF8String;
import dk.i1.diameter.AVP_Unsigned32;
import dk.i1.diameter.InvalidAVPLengthException;
import dk.i1.diameter.InvalidAddressTypeException;
import dk.i1.diameter.Message;

public class XDRUtil {
	
	private static Logger log = LogManager.getLogger(XDRUtil.class);
	public static Map<Integer, AVP> avpMap;

	public static Map<Integer, AVP> getAvpMap() {
		return avpMap;
	}

	public static void setAvpMap() {
		try {
			avpMap = XMLReader.readXMLFile2List(URLDecoder.decode(XDRUtil.class.getResource("/com/cmcc/volte/xdr/xml/DiameterAVP.xml").getFile(), "utf-8"));
		} catch (UnsupportedEncodingException e) {
			log.error("编码格式转换失败："+e);
			e.printStackTrace();
		}
	}

	public static List<Arrow> xdrArrow(SigXDR sigXDR) {
		//lvpin add 20161124
		sigXDR = SigXDRReassemble.reassemble(sigXDR);//20170727 lvpin：方法中新增了setPackgeType操作，用于标识SigXDR类型
		sigXDR = SigXDRSctpReassemble.reassemble(sigXDR);//20170802 lvpin:增加SCTP传输层的分片重组处理逻辑
		
		int sigXDRType = sigXDR.getPackgeType();
		if(sigXDRType==0){//ipv4
			Arrow arrow;
			List<Arrow> arrowList = new ArrayList<Arrow>();
			StringBuffer commentStr = new StringBuffer();
			StringBuffer remarkStr = new StringBuffer();
			InetAddress srcNode = null;
			InetAddress destNode = null;
			int srcNePort = 0;
			int destNePort  = 0;
			int dataSize = sigXDR.getHeader().getSize();
//			int Interface = sigXDR.getHeader().getInterface();
//			if(Interface != 19){
//				sigXDR = SigXDRReassemble.reassemble(sigXDR);
//			}
			// 不明原因在d时多执行了一次，待核查。
			for (int index = 0; index < dataSize; index++) {
				remarkStr = new StringBuffer();
				commentStr = new StringBuffer();
				byte[] load = sigXDR.getData().get(index).getLoad();
				int len = sigXDR.getData().get(index).getLen();
				int datetime_s = sigXDR.getData().get(index).getTime_s();
				long datetime_ns = sigXDR.getData().get(index).getTime_ns();
				byte[] srcNodebyte = new byte[4];
				byte[] destNodebyte = new byte[4];
				//获取端口号
				byte[] srcPortbyte = new byte[2];
				byte[] destPortbyte = new byte[2];
				srcNodebyte = Arrays.copyOfRange(load, 26, 30);
				destNodebyte = Arrays.copyOfRange(load, 30, 34);
				srcPortbyte = Arrays.copyOfRange(load, 34, 36);
				destPortbyte = Arrays.copyOfRange(load, 36, 38);
				int moveSize = 0;
				try {
					byte[] tmp = new byte[2];
					tmp[0] = load[12];
					tmp[1] = load[13];
					if("8100".equals(bytesToHexString(tmp))){//8100
						srcNodebyte = destNodebyte;
						destNodebyte = Arrays.copyOfRange(load, 34, 38);
						srcPortbyte = Arrays.copyOfRange(load, 38, 40);
						destPortbyte = Arrays.copyOfRange(load, 40, 42);
						moveSize = 4;
					}
					//0800  不要移位
					
					srcNode = InetAddress.getByAddress(srcNodebyte);
					destNode = InetAddress.getByAddress(destNodebyte);
					
					String srcPortStr = bytesToHexString(srcPortbyte);
					String destPortStr = bytesToHexString(destPortbyte);
					srcNePort = Integer.parseInt(srcPortStr,16);
					destNePort = Integer.parseInt(destPortStr,16);
					
//					System.out.println(srcNode+"=="+destNode);
				} catch (UnknownHostException e1) {
					e1.printStackTrace();
				}
				int interf_Id = sigXDR.getHeader().getInterface();
				if (interf_Id == 13 || interf_Id == 14 || interf_Id == 15 || interf_Id == 16 || interf_Id == 17 || interf_Id == 18 || interf_Id == 27) {
					parseSip(load, commentStr, remarkStr,moveSize);
				} else if (interf_Id == 20 || interf_Id == 21 || interf_Id == 22 || interf_Id == 23 || interf_Id == 24 || interf_Id == 25 || interf_Id == 26) {
					setAvpMap();
					parseDiameter(load, commentStr, remarkStr);
				} else if (interf_Id == 19) {
					parseGtp(load, commentStr, remarkStr,moveSize,len);
				}
				arrow = new Arrow();
				arrow.setComment(commentStr.toString());
				if(interf_Id != 19 && remarkStr.length() > 25){
					arrow.setRemark(remarkStr.substring(0, 25));
				}else{
					arrow.setRemark(remarkStr.toString());
				}
				arrow.setSrcNode(srcNode.getHostAddress());
				arrow.setDestNode(destNode.getHostAddress());
				arrow.setType(0);
				arrow.setDateTime_s(datetime_s);
				arrow.setDateTime_ns(datetime_ns);
				arrow.setSrcNePort(srcNePort);
				arrow.setDestNePort(destNePort);
				log.debug("消息内容" + arrow.getComment());
				log.debug("-----" + arrow.getRemark() + "------");
				log.debug("秒" + arrow.getDateTime_s());
				log.debug("纳秒" + arrow.getDateTime_ns());
				log.debug("srcIP: " + arrow.getSrcNode());
				log.debug("destIP: " + arrow.getDestNode());
				arrowList.add(arrow);
			}
			return arrowList;
		}else if(sigXDRType==1){//ipv6
			log.error("TODO TO Support IPv6 without ESP !!");
			return null;
		}else if(sigXDRType==2){//ipv6+ESP
			Arrow arrow;
			List<Arrow> arrowList = new ArrayList<Arrow>();
			StringBuffer commentStr = new StringBuffer();
			StringBuffer remarkStr = new StringBuffer();
			InetAddress srcNode = null;
			InetAddress destNode = null;
			int srcNePort = 0;
			int destNePort  = 0;
			int dataSize = sigXDR.getHeader().getSize();
//			int Interface = sigXDR.getHeader().getInterface();
//			if(Interface != 19){
//				sigXDR = SigXDRReassemble.reassemble(sigXDR);
//			}
			// 不明原因在d时多执行了一次，待核查。
			for (int index = 0; index < dataSize; index++) {
				remarkStr = new StringBuffer();
				commentStr = new StringBuffer();
				byte[] load = sigXDR.getData().get(index).getLoad();
				
				
				
				int len = sigXDR.getData().get(index).getLen();
				int datetime_s = sigXDR.getData().get(index).getTime_s();
				long datetime_ns = sigXDR.getData().get(index).getTime_ns();
				byte[] srcNodebyte = new byte[16];
				byte[] destNodebyte = new byte[16];
				//获取端口号
				byte[] srcPortbyte = new byte[2];
				byte[] destPortbyte = new byte[2];
				
				int moveSize = 0;
				try {
					byte[] tmp = new byte[2];
					tmp[0] = load[12];
					tmp[1] = load[13];
					if("8100".equals(bytesToHexString(tmp))){//8100 vLAN
						moveSize = 4;	
					}
					//0800  不要移位
					srcNodebyte = Arrays.copyOfRange(load, 22+moveSize, 38+moveSize);
					destNodebyte = Arrays.copyOfRange(load, 38+moveSize, 54+moveSize);
					
					byte ipv6Byte7 = load[20+moveSize];
					int nextHeader = ipv6Byte7;
					if(nextHeader == 44 ){//如果有分段扩展头，movesize+8
						moveSize = moveSize+8;
					}
					
					srcPortbyte = Arrays.copyOfRange(load, 54+8+moveSize, 56+8+moveSize);//+8是ESP Header
					destPortbyte = Arrays.copyOfRange(load, 56+8+moveSize, 58+8+moveSize);//+8是ESP Header
					
					srcNode = InetAddress.getByAddress(srcNodebyte);
					destNode = InetAddress.getByAddress(destNodebyte);
					
					String srcPortStr = bytesToHexString(srcPortbyte);
					String destPortStr = bytesToHexString(destPortbyte);
					srcNePort = Integer.parseInt(srcPortStr,16);
					destNePort = Integer.parseInt(destPortStr,16);
					
//					System.out.println(srcNode+"=="+destNode);
				} catch (UnknownHostException e1) {
					e1.printStackTrace();
				}
				
				int interf_Id = sigXDR.getHeader().getInterface();
				if (interf_Id == 13 || interf_Id == 14 || interf_Id == 15 || interf_Id == 16 || interf_Id == 17 || interf_Id == 18 || interf_Id == 27) {
					moveSize = moveSize+28;//20是Ipv6比ipv4多的20bytes，8是ESP Header，这里临时加在这里,IPv6的分段扩展头长度前面已经加了
					parseSip(load, commentStr, remarkStr,moveSize);
				} else if (interf_Id == 20 || interf_Id == 21 || interf_Id == 22 || interf_Id == 23 || interf_Id == 24 || interf_Id == 25 || interf_Id == 26) {
					setAvpMap();
					parseDiameter(load, commentStr, remarkStr);
				} else if (interf_Id == 19) {
					parseGtp(load, commentStr, remarkStr,moveSize,len);
				}
				arrow = new Arrow();
				arrow.setComment(commentStr.toString());
				if(interf_Id != 19 && remarkStr.length() > 25){
					arrow.setRemark(remarkStr.substring(0, 25));
				}else{
					arrow.setRemark(remarkStr.toString());
				}
				//由于前端不支持直接显示英文冒号，所以此处改为中文冒号
				arrow.setSrcNode(srcNode.getHostAddress());
				arrow.setDestNode(destNode.getHostAddress());
				
				arrow.setType(0);
				arrow.setDateTime_s(datetime_s);
				arrow.setDateTime_ns(datetime_ns);
				arrow.setSrcNePort(srcNePort);
				arrow.setDestNePort(destNePort);
				log.debug("消息内容" + arrow.getComment());
				log.debug("-- -" + arrow.getRemark() + "-- --");
				log.debug("秒" + arrow.getDateTime_s());
				log.debug("纳秒" + arrow.getDateTime_ns());
				log.debug("srcIP: " + arrow.getSrcNode());
				log.debug("destIP: " + arrow.getDestNode());
				arrowList.add(arrow);
//				System.out.println("XXXXXXXXXXXXXXXXXXXXX3-0 :  "+moveSize);
//				//System.out.println("XXXXXXXXXXXXXXXXXXXXX3-1 :  "+remarkStr.toString());
//				//System.out.println("XXXXXXXXXXXXXXXXXXXXX3-2 :  "+commentStr.toString());
//				System.out.println("XXXXXXXXXXXXXXXXXXXXX3-3 :  "+srcNode.getHostAddress());
//				System.out.println("XXXXXXXXXXXXXXXXXXXXX3-4 :  "+destNode.getHostAddress());
//				System.out.println("XXXXXXXXXXXXXXXXXXXXX3-5 :  "+srcNePort);
//				System.out.println("XXXXXXXXXXXXXXXXXXXXX3-6 :  "+destNePort);
//				System.out.println("XXXXXXXXXXXXXXXXXXXXX3-7 :  "+arrow.getDateTime_s());
//				System.out.println("XXXXXXXXXXXXXXXXXXXXX3-8 :  "+arrow.getDateTime_ns());
//				System.out.println("XXXXXXXXXXXXXXXXXXXXX3-9 :  "+arrow.getRemark());
//				System.out.println("XXXXXXXXXXXXXXXXXXXXX3-10 :  "+arrow.getComment());
			}
			return arrowList;
		}else {
			log.error("Unkonw SigXDR Type !");
			return null;
		}

	}

	private static void parseDiameter(byte[] load, StringBuffer commentStr, StringBuffer remarkStr) {
		Message message = new Message();
		int diameterStart = getDiameterStart(load);
		int messageLength = load.length;
		int DiameterLength = messageLength - diameterStart;
		message.decode(load, diameterStart, DiameterLength);
		log.debug("Version:0x01<br>" + "Length: " + DiameterLength + "<br>" + "Flags: 0x" + Integer.toHexString(message.hdr.getCommand_flags() & 0xff));
		commentStr.append("Version:0x01<br>" + "Length: " + DiameterLength + "<br>" + "Flags: 0x" + Integer.toHexString(message.hdr.getCommand_flags() & 0xff) + "<br>");
		readProperties(message, commentStr);
		readRemarkProperties(message, remarkStr);
		log.debug("Hop_by_hop Identifier: 0x" + Integer.toHexString(message.hdr.hop_by_hop_identifier) + "<br>End_to_end Identifier: 0x"
				+ Integer.toHexString(message.hdr.end_to_end_identifier));
		commentStr.append("Hop_by_hop Identifier: 0x" + fill(Integer.toHexString(message.hdr.hop_by_hop_identifier), 8, '0') + "<br>End_to_end Identifier: 0x"
				+ fill(Integer.toHexString(message.hdr.end_to_end_identifier), 8, '0') + "<br>");
		for (int i = 0; i < message.size(); i++) {
			try {
				parseAVP(message.get(i), commentStr);
			} catch (InvalidAVPLengthException e) {
				log.error("类型转换失败："+e);
				e.printStackTrace();
			}
		}
	}

	private static void parseSip(byte[] load, StringBuffer commentStr, StringBuffer remarkStr,int moveSize) {
		String s = new String();
		s = bytesToString(load);
//		System.out.println("\nYYYYYYYYYYYYYYYYYYYYYYYYYYYY-1:  parseSip \n"+s);
		s = s.replaceAll("<", " ");
		s = s.replaceAll(">", " ");
		s = s.replaceAll("\r\n", "<br>");
		String s1 = s.substring(moveSize, 3+moveSize);
//		System.out.println("\nYYYYYYYYYYYYYYYYYYYYYYYYYYYY-2:  parseSip \n"+s1);
//		 System.out.print("消息类型："+s1+"--,");
		// 生成新的txt文件
		if (s1.equalsIgnoreCase("SIP")) {
			for (int j = 50+moveSize; j < load.length; j++) {
				// 判断消息是请求还是响应。请求消息先出现回车，响应消息先出现空格
				if ((char) load[j] == 32) {
					break;
				} else {
					// System.out.print((char) load[j]);
					remarkStr.append((char) load[j]);
				}
			}
		} else if (s1.equalsIgnoreCase("REG")) {
			// 42指pcap头42字节，第43字节开始是sip消息
			for (int j = 42+moveSize; j < load.length; j++) {
				if (load[j] == 32) {
					break;
				} else {
					// System.out.print((char) load[j]);
					remarkStr.append((char) load[j]);
				}
			}
		} else {
			// 42指pcap头42字节，第43字节开始是sip消息
			for (int j = 42+moveSize; j < load.length; j++) {
				if (load[j] == 32) {
					break;
				} else {
					// System.out.print((char) load[j]);
					remarkStr.append((char) load[j]);
				}
			}

		}
		if(moveSize>20){//当IPv6+ESP时，如果有分片，此值为20+8+8，如果没有分片，此值为20+8，其中20是IPv6比IPv4多的20，8分别为ESP Header和Fragmentation Header
			int espPadLengthPosition = load.length-14;//找到ESP Pad Length字节的位置
			byte espPadLengthByte = load[espPadLengthPosition];
			int espPadLengthInt = espPadLengthByte;//获得ESP Pad Length的只
//			System.out.println("\nYYYYYYYYYYYYYYYYYYYYYYYYYYYY-3:  parseSip \n"+espPadLengthPosition);
//			System.out.println("\nYYYYYYYYYYYYYYYYYYYYYYYYYYYY-4:  parseSip \n"+espPadLengthInt);
			s = s.substring(moveSize, s.length()-espPadLengthInt-14);//去掉ESP tailer
		} else{
			 s = s.substring(moveSize, s.length());
		}
		commentStr.append(s);
	}
	
	private static Map<Integer,byte[]> getGtpByte(byte[] load,int moveSize, int len){
		Map<Integer,byte[]> map = new HashMap<Integer,byte[]>();
		int startLength = 54;
		boolean bool = true;
		while(bool){
			int type = 0;
			int size = 0;
			byte[] tmptype = new byte[1];
			tmptype[0] = load[startLength+moveSize];
			startLength ++;
			type = bytesToInt(tmptype);//类型
			
			byte[] tmpSize = new byte[2];
			tmpSize[1] = load[startLength+moveSize];
			startLength ++;
			tmpSize[0] = load[startLength+moveSize];
			startLength ++;
			size = bytesToInt(tmpSize);//总长度
			
			startLength ++;//一个没有用的字节跳过
			byte[] tmpinfo = new byte[size];//改类型的信息字节
			for(int i = 0; i < size; i++){
				tmpinfo[i] = (byte) (load[startLength+moveSize] & 0x000000ff);
				startLength ++;
			}
			map.put(type, tmpinfo);//key类型,value对应的字节
			if(startLength >= (len-18)){
				bool = false;
			}
		}
		return map;
	}

	private static void parseGtp(byte[] load, StringBuffer commentStr, StringBuffer remarkStr,int moveSize,int len) {
		int gtpType = load[43+moveSize] & 0x000000ff;
		switch (gtpType) {
			case (25): {
				Map<Integer,byte[]> mapInfo = getGtpByte(load,moveSize,len);
				remarkStr.append("SRVCC PS to CS Request");
				byte[] tmp = new byte[1];
				tmp[0] = load[42+moveSize];
				commentStr.append("Flags: 0x" + bytesToHexString(tmp) + "<br>");
				commentStr.append("Message Type: " + remarkStr.toString() + " (" + String.valueOf(load[43+moveSize] & 0x000000ff) + ")<br>");
				tmp = new byte[2];
				tmp[1] = load[44+moveSize];
				tmp[0] = load[45+moveSize];
				commentStr.append("Message Length: " + bytesToInt(tmp) + "<br>");
				tmp = new byte[4];
				tmp[0] = load[49+moveSize];
				tmp[1] = load[48+moveSize];
				tmp[2] = load[47+moveSize];
				tmp[3] = load[46+moveSize];
				commentStr.append("Tunnel Endpoint Identifier: " + bytesToInt4(tmp, 0) + "<br>");
				tmp = new byte[4];
				tmp[0] = load[52+moveSize];
				tmp[1] = load[51+moveSize];
				tmp[2] = load[50+moveSize];
				commentStr.append("Sequence Number: " + bytesToInt3(tmp, 0) + "<br>");
				commentStr.append("Spare: " + String.valueOf(load[53+moveSize] & 0x000000ff) + "<br>");
				commentStr.append("International Mobile Subscriber Identity (IMSI) : " + parseIMSI(mapInfo.get(1), false, 8) + "<br>");
				commentStr.append("Mobile Equipment Identity (MEI) : " + parseIMSI(mapInfo.get(75), false, 8) + "<br>");
				String svFlags = bytesToHexString(mapInfo.get(60));
				if(svFlags != null)
				commentStr.append("Sv Flags : 0x" + svFlags + "<br>");
				try {
					commentStr.append("IP Address : IPv4 " + InetAddress.getByAddress(mapInfo.get(74)).getHostAddress() + "<br>");
				} catch (UnknownHostException e1) {
					e1.printStackTrace();
				}
				commentStr.append("TEID-C : " + new BigInteger(bytesToHexString(mapInfo.get(59)), 16) + "<br>");
				commentStr.append("MSISDN : " + parseIMSI(mapInfo.get(76), false, 7) + "<br>");
				byte[] stnsrByte = mapInfo.get(51);
				tmp = new byte[5];
				for(int i = 0 ;i<stnsrByte.length-1 ;i++){
					tmp[i] = stnsrByte[i+1];
				}
//				tmp[0] = stnsrByte[1];
//				tmp[1] = stnsrByte[2];
//				tmp[2] = stnsrByte[3];
//				tmp[3] = stnsrByte[4];
//				tmp[4] = stnsrByte[5];
				commentStr.append("STN-SR : Address digits : " + parseIMSI(tmp, false, 5) + "<br>");
				commentStr.append("MM Context for E-UTRAN (v)SRVCC : 0x"+bytesToHexString(mapInfo.get(54))+"<br>");
				String sttc = bytesToHexString(mapInfo.get(52))==null?"":bytesToHexString(mapInfo.get(52));
				commentStr.append("Source to Target Transparent Container : 0x"+sttc+"<br>");
				commentStr.append("Target Global Cell ID : 0x"+bytesToHexString(mapInfo.get(58))+"<br>");
				break;
			}
			case (26): {
				Map<Integer,byte[]> mapInfo = getGtpByte(load,moveSize,len);
				remarkStr.append("SRVCC PS to CS Response");
				byte[] tmp = new byte[1];
				tmp[0] = load[42+moveSize];
				commentStr.append("Flags: 0x" + bytesToHexString(tmp) + "<br>");
				commentStr.append("Message Type: " + remarkStr.toString() + " (" + String.valueOf(load[43+moveSize] & 0x000000ff) + ")<br>");
				tmp = new byte[2];
				tmp[1] = load[44+moveSize];
				tmp[0] = load[45+moveSize];
				commentStr.append("Message Length: " + bytesToInt(tmp) + "<br>");
				tmp = new byte[4];
				tmp[0] = load[49+moveSize];
				tmp[1] = load[48+moveSize];
				tmp[2] = load[47+moveSize];
				tmp[3] = load[46+moveSize];
				commentStr.append("Tunnel Endpoint Identifier: " + bytesToInt4(tmp, 0) + "<br>");
				tmp = new byte[3];
				tmp[0] = load[52+moveSize];
				tmp[1] = load[51+moveSize];
				tmp[2] = load[50+moveSize];
				commentStr.append("Sequence Number: " + bytesToInt3(tmp, 0) + "<br>");
				commentStr.append("Spare : " + String.valueOf(load[53+moveSize] & 0x000000ff) + "<br>");
				
				commentStr.append("Cause : Request accepted (" + String.valueOf(mapInfo.get(2)[0] & 0x000000ff) + ")<br>");
				commentStr.append("TEID-C : 0x" + new BigInteger(bytesToHexString(mapInfo.get(59)), 16) + "<br>");
				String sttc = bytesToHexString(mapInfo.get(53))==null?"":bytesToHexString(mapInfo.get(53));
				commentStr.append("Source to Target Transparent Container : 0x"+sttc+"<br>");
				break;
			}
			case (27): {
				Map<Integer,byte[]> mapInfo = getGtpByte(load,moveSize,len);
				remarkStr.append("SRVCC PS to CS Complete Notification");
				byte[] tmp = new byte[1];
				tmp[0] = load[42+moveSize];
				commentStr.append("Flags: 0x" + bytesToHexString(tmp) + "<br>");
				commentStr.append("Message Type: " + remarkStr.toString() + " (" + String.valueOf(load[43+moveSize] & 0x000000ff) + ")<br>");
				tmp = new byte[2];
				tmp[1] = load[44+moveSize];
				tmp[0] = load[45+moveSize];
				commentStr.append("Message Length: " + bytesToInt(tmp) + "<br>");
				tmp = new byte[4];
				tmp[0] = load[49+moveSize];
				tmp[1] = load[48+moveSize];
				tmp[2] = load[47+moveSize];
				tmp[3] = load[46+moveSize];
				commentStr.append("Tunnel Endpoint Identifier: " + bytesToInt4(tmp, 0) + "<br>");
				tmp = new byte[4];
				tmp[0] = load[52+moveSize];
				tmp[1] = load[51+moveSize];
				tmp[2] = load[50+moveSize];
				commentStr.append("Sequence Number: " + bytesToInt3(tmp, 0) + "<br>");
				commentStr.append("Spare: " + String.valueOf(load[53+moveSize] & 0x000000ff) + "<br>");
				commentStr.append("International Mobile Subscriber Identity (IMSI) : " + parseIMSI(mapInfo.get(1), false, 8) + "<br>");
				break;
			}
			case (28): {
				Map<Integer,byte[]> mapInfo = getGtpByte(load,moveSize,len);
				remarkStr.append("SRVCC PS to CS Complete Acknowledge");
				byte[] tmp = new byte[1];
				tmp[0] = load[42+moveSize];
				commentStr.append("Flags: 0x" + bytesToHexString(tmp) + "<br>");
				commentStr.append("Message Type: " + remarkStr.toString() + " (" + String.valueOf(load[43+moveSize] & 0x000000ff) + ")<br>");
				tmp = new byte[2];
				tmp[1] = load[44+moveSize];
				tmp[0] = load[45+moveSize];
				commentStr.append("Message Length: " + bytesToInt(tmp) + "<br>");
				tmp = new byte[4];
				tmp[0] = load[49+moveSize];
				tmp[1] = load[48+moveSize];
				tmp[2] = load[47+moveSize];
				tmp[3] = load[46+moveSize];
				commentStr.append("Tunnel Endpoint Identifier: " + bytesToInt4(tmp, 0) + "<br>");
				tmp = new byte[4];
				tmp[0] = load[52+moveSize];
				tmp[1] = load[51+moveSize];
				tmp[2] = load[50+moveSize];
				commentStr.append("Sequence Number: " + bytesToInt3(tmp, 0) + "<br>");
				commentStr.append("Spare: " + String.valueOf(load[53+moveSize] & 0x000000ff) + "<br>");
				commentStr.append("Cause : Request accepted (" + String.valueOf(mapInfo.get(2)[0] & 0x000000ff) + ")<br>");
				
				break;
			}
			case (29): {
				Map<Integer,byte[]> mapInfo = getGtpByte(load,moveSize,len);
				remarkStr.append("SRVCC PS to CS Cancel Notification");
				byte[] tmp = new byte[1];
				tmp[0] = load[42+moveSize];
				commentStr.append("Flags: 0x" + bytesToHexString(tmp) + "<br>");
				commentStr.append("Message Type: " + remarkStr.toString() + " (" + String.valueOf(load[43+moveSize] & 0x000000ff) + ")<br>");
				tmp = new byte[2];
				tmp[1] = load[44+moveSize];
				tmp[0] = load[45+moveSize];
				commentStr.append("Message Length: " + bytesToInt(tmp) + "<br>");
				tmp = new byte[4];
				tmp[0] = load[49+moveSize];
				tmp[1] = load[48+moveSize];
				tmp[2] = load[47+moveSize];
				tmp[3] = load[46+moveSize];
				commentStr.append("Tunnel Endpoint Identifier: " + bytesToInt4(tmp, 0) + "<br>");
				tmp = new byte[4];
				tmp[0] = load[52+moveSize];
				tmp[1] = load[51+moveSize];
				tmp[2] = load[50+moveSize];
				commentStr.append("Sequence Number: " + bytesToInt3(tmp, 0) + "<br>");
				commentStr.append("Spare : " + String.valueOf(load[53+moveSize] & 0x000000ff) + "<br>");
				
				commentStr.append("International Mobile Subscriber Identity (IMSI) : " + parseIMSI(mapInfo.get(1), false, 8) + "<br>");
				String svFlags = bytesToHexString(mapInfo.get(56)) == null ?"":"0x"+bytesToHexString(mapInfo.get(56));
				
				commentStr.append("SRVCC Cause : " + svFlags + "<br>");
				commentStr.append("Mobile Equipment Identity (MEI) : " + parseIMSI(mapInfo.get(75), false, 8) + "<br>");
	//			commentStr.append("Private Extension : 0x"+bytesToHexString(mapInfo.get(255))+"<br>");
	
				break;
			}
			case (30): {
				Map<Integer,byte[]> mapInfo = getGtpByte(load,moveSize,len);
				remarkStr.append("SRVCC PS to CS Cancel Acknowledge");
				byte[] tmp = new byte[1];
				tmp[0] = load[42+moveSize];
				commentStr.append("Flags: 0x" + bytesToHexString(tmp) + "<br>");
				commentStr.append("Message Type: " + remarkStr.toString() + " (" + String.valueOf(load[43+moveSize] & 0x000000ff) + ")<br>");
				tmp = new byte[2];
				tmp[1] = load[44+moveSize];
				tmp[0] = load[45+moveSize];
				commentStr.append("Message Length: " + bytesToInt(tmp) + "<br>");
				tmp = new byte[4];
				tmp[0] = load[49+moveSize];
				tmp[1] = load[48+moveSize];
				tmp[2] = load[47+moveSize];
				tmp[3] = load[46+moveSize];
				commentStr.append("Tunnel Endpoint Identifier: " + bytesToInt4(tmp, 0) + "<br>");
				tmp = new byte[4];
				tmp[0] = load[52+moveSize];
				tmp[1] = load[51+moveSize];
				tmp[2] = load[50+moveSize];
				commentStr.append("Sequence Number: " + bytesToInt3(tmp, 0) + "<br>");
				commentStr.append("Spare : " + String.valueOf(load[53+moveSize] & 0x000000ff) + "<br>");
				commentStr.append("Cause : Request accepted (" + String.valueOf(mapInfo.get(2)[0] & 0x000000ff) + ")<br>");
				String svFlags = bytesToHexString(mapInfo.get(60)) == null ?"":bytesToHexString(mapInfo.get(60));
				commentStr.append("Sv Flags : 0x" + svFlags + "<br>");
				break;
				}
			case (31): {
				remarkStr.append("SRVCC CS to PS Request");
				break;
			}
			case (32): {
				remarkStr.append("Reserved for GTPv2");
				break;
			}
		}
		
		log.debug(commentStr);
	}

	public static String parseIMSI(byte[] bytes, boolean flag, int size) {
		if(bytes == null){
			return "";
		}
		StringBuffer tmp = new StringBuffer();
		int tmpInt = 0;
		for (int i = 0; i < size; i++) {
			if ((size-1) != i) {
				int bs = bytes[i] & 0xFF;
//				System.out.println("bs=========="+bs);
				if(bs != 238){//检测是否为ee,如果是是则直接展示成ee
					tmpInt = Integer.parseInt(Integer.toHexString(bs));
					tmp.append(tmpInt % 10);
					tmp.append(tmpInt / 10);
				}else{
					tmp.append("ee");
				}
			} else {//如果是最后一位需要判断如果是单数，则去掉F，如果是双数则直接翻转
				if (flag) {
					tmp.append(0);
				} else {
					int bs = bytes[i] & 0xFF;
//					System.out.println("bs2=========="+bs);
					if(bs != 238){
						String str = Integer.toHexString(bs);
						if(str.indexOf("f") > -1 || str.indexOf("F") > -1){
							tmp.append(str.replaceAll("f", "").replaceAll("F", ""));
						}else{
							tmpInt = Integer.parseInt(str);
							tmp.append(tmpInt % 10);
							tmp.append(tmpInt / 10);
						}
					}else{
						tmp.append("ee");
					}
				}

			}
		}
		return tmp.toString();
	}
	public static void main(String[] args) {
		System.out.println(Integer.toHexString(-15));
		int tmpInt = 69;
		System.out.println((tmpInt % 10)+"=="+tmpInt / 10);
	}

//	public static String parseMSISDN(byte[] bytes) {
//		StringBuffer tmp = new StringBuffer();
//		int tmpInt = 0;
//		for (int i = 0; i < 7; i++) {
//			if (6 != i) {
////				tmpInt = Integer.parseInt(Integer.toHexString(bytes[i] & 0xFF));
//				tmpInt = Integer.parseInt((bytes[i] & 0xFF)+"");
//				tmp.append(tmpInt % 10);
//				tmp.append(tmpInt / 10);
//			} else {
//				String str = Integer.toHexString(bytes[i]);
//				if(str.indexOf("f") > -1){
//					tmp.append(str.replaceAll("f", ""));
//				}else{
//					tmpInt = Integer.parseInt(str);
//					tmp.append(tmpInt % 10);
//					tmp.append(tmpInt / 10);
//				}
//			}
//		}
//		return tmp.toString();
//	}

	public static String parseSTNSR(byte[] bytes) {
		StringBuffer tmp = new StringBuffer();
		int tmpInt = 0;
		for (int i = 0; i < 6; i++) {
//			tmpInt = Integer.parseInt(Integer.toHexString(bytes[i] & 0xFF));
			tmpInt = Integer.parseInt((bytes[i] & 0xFF)+"");
			tmp.append(tmpInt / 10);
			tmp.append(tmpInt % 10);
		}
		return tmp.toString();
	}

	public static String bytesToString(byte[] b) {

		StringBuffer result = new StringBuffer("");
		for (int i = 42; i < b.length; i++) {
			result.append((char) (b[i] & 0xff));
		}
		return result.toString();
	}

	// 得到diameter消息开始的字节数diameterStart
	private static int getDiameterStart(byte[] load) {
		int diameterStart = 0;
		if (load[23] == 6) {
			diameterStart = 54;
		} else if (load[23] == -124) {
			// 46代表到第一个chunk type的字节数
			int Chunktypenumber = 46;
			while (!(load[Chunktypenumber] == 0)) {
				Chunktypenumber = Chunktypenumber + 16;
			}
			// chunk type后面第二、三个字节代表length，将其转化为十进制
			int datalength = (load[Chunktypenumber + 2] << 8) + (load[Chunktypenumber + 3] & 0xff);
			// datalength代表chunkdata+diameter的总字节数，由（datalength-16）即得到Diameterlength
			diameterStart = load.length - (datalength - 16);//(SCTP中chunklength值是包括data chunk和diameter长度之和)
		}
		return diameterStart;
	}

	private static void readProperties(Message message, StringBuffer commentStr) {
		// 取Header里面的application_id字段，与配置文件比较，打印其应用类型
		String commandcode = String.valueOf(message.hdr.command_code);
		Properties properties = new Properties();
		// 读DiameterHeader配置文件
		try {
			properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config/DiameterHeader.properties"));
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		if (properties.containsKey(commandcode)) {
			if (message.hdr.isRequest()) {
				// log.debug("Command-Code: " + message.hdr.command_code
				// + " " + properties.getProperty(commandcode)
				// + "-Request");
				commentStr.append("Command-Code: " + message.hdr.command_code + " " + properties.getProperty(commandcode) + "-Request" + "<br>");
			} else {
				// System.out
				// .println("Command-Code: " + message.hdr.command_code
				// + " " + properties.getProperty(commandcode)
				// + "-Answer");
				commentStr.append("Command-Code: " + message.hdr.command_code + " " + properties.getProperty(commandcode) + "-Answer" + "<br>");
			}
		} else {
			// log.debug("Command-Code: " + message.hdr.command_code);
			commentStr.append("Command-Code: " + message.hdr.command_code + "<br>");
		}
		// 取Header里面的application_id字段，与配置文件比较，打印其应用类型
		String ApplicationId = String.valueOf(message.hdr.application_id);
		if (properties.containsKey(ApplicationId)) {
			// log.debug("ApplicationId: "
			// + properties.getProperty(ApplicationId) + " ("
			// + message.hdr.application_id + ")");
			commentStr.append("ApplicationId: " + properties.getProperty(ApplicationId) + " (" + message.hdr.application_id + ")<br>");
		} else {
			// log.debug("ApplicationId: " + message.hdr.application_id
			// + "(Diameter Common Messages)");
			commentStr.append("ApplicationId: " + message.hdr.application_id + "(Diameter Common Messages)<br>");
		}

	}

	private static void readRemarkProperties(Message message, StringBuffer remarkStr) {
		String commandcode = String.valueOf(message.hdr.command_code);
		Properties properties = new Properties();
		// 读DiameterHeader配置文件

		try {
			properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config/Remark.properties"));
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		if (properties.containsKey(commandcode)) {
			if (message.hdr.isRequest()) {
				remarkStr.append(properties.getProperty(commandcode) + "R");
			} else {
				remarkStr.append(properties.getProperty(commandcode) + "A");
			}
		} else {
			remarkStr.append("Command-Code: " + message.hdr.command_code + "<br>");
		}
	}

	private static void parseAVP(AVP avp, StringBuffer commentStr) throws InvalidAVPLengthException {
		// System.out.print("AVP code: " + avp.getCode());
		commentStr.append("AVP code: " + avp.getCode());

		// 此处需加上 try/catch，防止配置文件中没有对应的avp-code-name

		AVP avpConf = avpMap.get(avp.getCode());
		if (avpConf == null || avpConf.toString().length() == 0)
			return;
		// System.out.print(" " + avpConf.getAvp_name());
		commentStr.append(" " + avpConf.getAvp_name());

		String DataType = avpConf.getAvp_datatype();

		// System.out.print("	Flags: 0x"
		// + Integer.toHexString(avp.getFlags() & 0xff));
		commentStr.append("	Flags: 0x" + Integer.toHexString(avp.getFlags() & 0xff));

		// 得到AVP的Code：avp.code();
		// 查配置文件，得到编码类型
		if (avp.isVendorSpecific()) {
			// System.out.print("	Length: " + (avp.queryPayload().length + 12));
			commentStr.append("	Length: " + (avp.queryPayload().length + 12));
		} else {
			// System.out.print("	Length: " + (avp.queryPayload().length + 8));
			commentStr.append("	Length: " + (avp.queryPayload().length + 8));
		}

		if (avp.isVendorSpecific()) {
			// System.out.print("	vendor Id: " + avp.vendor_id);
			commentStr.append("	vendor Id: " + avp.vendor_id);
		}

		if ("UTF8String".equals(DataType)) {
			AVP_UTF8String temp = new AVP_UTF8String(avp);
			String value = temp.queryValue();
			// log.debug("	Value: " + value);
			commentStr.append("	Value: " + value + "<br>");

		}
		if ("Integer32".equals(DataType)) {
			AVP_Integer32 temp = new AVP_Integer32(avp);
			int value = temp.queryValue();
			// log.debug("	Value: " + value);
			commentStr.append("	Value: " + value + "<br>");

		}
		if ("Integer64".equals(DataType)) {
			AVP_Integer64 temp = new AVP_Integer64(avp);
			long value = temp.queryValue();
			// log.debug("	Value: " + value);
			commentStr.append("	Value: " + value + "<br>");
		}
		if ("Unsigned32".equals(DataType)) {
			AVP_Unsigned32 temp = new AVP_Unsigned32(avp);
			int value = temp.queryValue();
			// log.debug("	Value: " + value);
			commentStr.append("	Value: " + value + "<br>");
		}
		if ("Float32".equals(DataType)) {
			AVP_Float32 temp = new AVP_Float32(avp);
			float value = temp.queryValue();
			// log.debug("	Value: " + value);
			commentStr.append("	Value: " + value + "<br>");
		}
		if ("Float64".equals(DataType)) {
			AVP_Float64 temp = new AVP_Float64(avp);
			double value = temp.queryValue();
			// log.debug("	Value: " + value);
			commentStr.append("	Value: " + value + "<br>");
		}
		if ("Integer32".equals(DataType)) {
			AVP_Integer32 temp = new AVP_Integer32(avp);
			int value = temp.queryValue();
			// log.debug("	Value: " + value);
			commentStr.append("	Value: " + value + "<br>");
		}
		if ("Enumerated".equals(DataType)) {
			AVP_Integer32 temp = new AVP_Integer32(avp);
			int value = temp.queryValue();
			// log.debug("	Value: " +
			// avpConf.getEnumavpMap().get(value)
			// + "(" + value + ")");
			commentStr.append("	Value: " + avpConf.getEnumavpMap().get(value) + "(" + value + ")<br>");

			// log.debug(avp.getEnumavpMap().get(value));
		}
		if ("OctetString".equals(DataType)) {
			// System.out.print("	Value: ");
			commentStr.append("	Value: ");
			AVP_OctetString temp = new AVP_OctetString(avp);
			byte[] value = temp.queryValue();
			
			if(avp.getCode()==97){
				String val = HashCode.fromBytes(value).toString();
				byte[] bytes = HashCode.fromString(val.substring(4)).asBytes();
				String address;
				try {
					address = InetAddress.getByAddress(bytes).getHostAddress();
					commentStr.append(address);
				} catch (UnknownHostException e) {
					// TODO Auto-generated catch block
					log.error("IP地址获取失败："+e);
					e.printStackTrace();
				}
			}else {
				commentStr.append(new String(value));
			}

//			for (int k = 0; k < value.length; k++) {
//				// System.out.print(value[k]);
//				commentStr.append(value[k]);
//			}
			// log.debug();
			commentStr.append("<br>");

		}
		if ("Address".equals(DataType)) {
			AVP_Address temp;
			try {
				// System.out.print("	Value: ");
				commentStr.append("	Value: ");
				temp = new AVP_Address(avp);
				InetAddress value = temp.queryAddress();
				if (temp.queryPayload().length == 6) {
					// System.out.print("IPv4:");
					commentStr.append("IPv4:");
				} else if (temp.queryPayload().length == 18) {
					// System.out.print("IPv6:");
					commentStr.append("IPv6:");
				}
				// log.debug(value.getHostAddress());
				commentStr.append(value.getHostAddress() + "<br>");
			} catch (InvalidAddressTypeException e) {
				log.error("类型转换失败："+e);
				e.printStackTrace();
			}

		}
		if ("Time".equals(DataType)) {
			AVP_Time temp = new AVP_Time(avp);
			Date value = (Date) temp.queryDate();
			// log.debug("	Value: " + value);
			commentStr.append("	Value: " + value + "<br>");
		}

		if ("Grouped".equals(DataType)) {

			try {
				AVP_Grouped temp = new AVP_Grouped(avp);
				AVP[] value = temp.queryAVPs();
				// System.out.print("	Value: (" + value.length + "AVPs)");
				commentStr.append("	Value: (" + value.length + "AVPs)");

				for (int avpnum = 0; avpnum < value.length; avpnum++) {
					parseAVP(value[avpnum], commentStr);
				}
			} catch (InvalidAVPLengthException e) {
				AVP_UTF8String temp = new AVP_UTF8String(avp);
				String value = temp.queryValue();
				// log.debug("	Value: " + value);
				commentStr.append("	Value: " + value + "<br>");

			}
		}

	}

	public static byte[] shortToByteArray(short s) {
		byte[] shortBuf = new byte[2];
		for (int i = 0; i < 2; i++) {
			int offset = (shortBuf.length - 1 - i) * 8;
			shortBuf[i] = (byte) ((s >>> offset) & 0xff);
		}
		return shortBuf;
	}

	public static byte[] intToByteArray(int s) {
		byte[] shortBuf = new byte[4];
		for (int i = 0; i < 4; i++) {
			int offset = (shortBuf.length - 1 - i) * 8;
			shortBuf[i] = (byte) ((s >>> offset) & 0xff);
		}
		return shortBuf;
	}

	public static byte[] list2byteArray(List<Byte> byteList) {
		int size = byteList.size();
		byte[] byteArray = new byte[size];
		for (int index = 0; index < size; index++) {
			byteArray[index] = byteList.get(index);
		}
		return byteArray;
	}

	private static String fill(String input, int size, char symbol) {

		while (input.length() < size) {
			input = symbol + input;
		}
		return input;
	}

	public static String bytes2HexString(byte[] b) {
		String ret = "";
		for (int i = 0; i < b.length; i++) {
			String hex = Integer.toHexString(b[i] & 0xFF);
			if (hex.length() == 1) {
				hex = '0' + hex;
			}
			ret += hex.toUpperCase();
		}
		return ret;
	}

	public static byte[] rotateByteArray(byte[] bytes) {
		byte[] tmp = new byte[bytes.length];

		for (int i = bytes.length - 1; i >= 0; i--) {
			tmp[bytes.length - 1 - i] = bytes[i];
		}
		return tmp;
	}

	public static int bytesToInt(byte[] bytes) {
		int addr = bytes[0] & 0xFF;
		for (int i = 1; i < bytes.length; i++) {
			int power = (int) Math.pow(100, i - 1);
			addr |= ((bytes[i] << 8 * i) & 0xFF00 * power);
		}
		return addr;
	}

	public static String bytesToHexString(byte[] src) {
		StringBuilder stringBuilder = new StringBuilder("");
		if (src == null || src.length <= 0) {
			return null;
		}
		for (int i = 0; i < src.length; i++) {
			int v = src[i] & 0xFF;
			String hv = Integer.toHexString(v);
			if (hv.length() < 2) {
				stringBuilder.append(0);
			}
			stringBuilder.append(hv);
		}
		return stringBuilder.toString();
	}

	public static int bytesToInt3(byte[] ary, int offset) {
		int value;
		value = (int) ((ary[offset] & 0xFF) | ((ary[offset + 1] << 8) & 0xFF00) | ((ary[offset + 2] << 16) & 0xFF0000));
		return value;
	}

	public static int bytesToInt4(byte[] ary, int offset) {
		int value;
		value = (int) ((ary[offset] & 0xFF) | ((ary[offset + 1] << 8) & 0xFF00) | ((ary[offset + 2] << 16) & 0xFF0000) | ((ary[offset + 3] << 24) & 0xFF000000));
		return value;
	}

	public static String toIpAddress(byte[] bytes) {
		if (bytes[0] == -1 && bytes.length > 4) {
			bytes = Arrays.copyOfRange(bytes, bytes.length - 4, bytes.length);
		}
		try {
			return InetAddress.getByAddress(bytes).getHostAddress();
		} catch (UnknownHostException e) {
			throw new RuntimeException(e);
		}
	}

}